﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Sherwood.Security;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Text.RegularExpressions;
using System.Security.Cryptography;


namespace Sherwood.Security.Tests
{
    [TestClass]
    public class RsaTest
    {
        //Test context variables
        private Rsa RSA { get; set; }
        private string OriginalMessage { get; set; }
        private string EncryptedMessage { get; set; }
        private string DecryptedMessage { get; set; }
        private string MessageSignature { get; set; }


        [TestMethod]
        public void FromPrivateKeyTest()
        {
            //Arrange
            string privateKey = "";
            string publicKey = "";
            Sherwood.Security.KeyGenerationUtility.MainWindow.GenerateKeyPair(out publicKey, out privateKey);
            OriginalMessage = DateTime.Now.ToString();
            DecryptedMessage = null;
            EncryptedMessage = null;

            //Act
            RSA = Rsa.FromPrivateKey(privateKey);
            

            //Assert
            Assert.IsNotNull(RSA);

            try
            {
                PublicEncryptTest();
                PrivateDecryptTest();
                SHA1SignTest();
                SHA1VerifyTest();
            }
            catch (Exception ex)
            {
                Assert.Fail("Encryption and signing tests should not have thrown an exception. The following exception was thrown {0}.", ex.Message);
            }

        }


        [TestMethod]
        public void FromPublicKeyTest()
        {
            //Arrange
            string privateKey = "";
            string publicKey = "";
            Sherwood.Security.KeyGenerationUtility.MainWindow.GenerateKeyPair(out publicKey, out privateKey);
            OriginalMessage = DateTime.Now.ToString();

            //Act
            RSA = Rsa.FromPublicKey(publicKey);
            PublicEncryptTest();
            bool privateDecryptFailed = false;
            try
            {
                PrivateDecryptTest();
            }
            catch
            {
                privateDecryptFailed = true;
            }
            bool shasignfailed = false;
            try
            {
                SHA1SignTest();
            }
            catch
            {
                shasignfailed = true;
            }

            //Assert
            Assert.IsNotNull(RSA);
            Assert.IsTrue(privateDecryptFailed, "Private decryption should have failed since a public key was used.");
            Assert.IsTrue(shasignfailed, "SHA signing should have failed since a public key was used");
        }


        [TestMethod]
        public void GenerateKeyPairTest()
        {
            //Arrange
            string privateKey = null;
            string publicKey = null;

            //Act
            Sherwood.Security.KeyGenerationUtility.MainWindow.GenerateKeyPair(out publicKey, out privateKey);

            //Assert
            Assert.IsNotNull(publicKey);
            Assert.IsNotNull(privateKey);
            Assert.IsTrue(privateKey.Length > publicKey.Length);

        }

        [TestMethod]
        public void PublicEncryptTest()
        {
            //Arrange
            EncryptedMessage = null;
            if (RSA == null)
            {
                string privateKey = "";
                string publicKey = "";
                Sherwood.Security.KeyGenerationUtility.MainWindow.GenerateKeyPair(out publicKey, out privateKey);
                OriginalMessage = DateTime.Now.ToString();
                RSA = Rsa.FromPrivateKey(privateKey);
            }

            //Act
            EncryptedMessage = RSA.PublicEncrypt(OriginalMessage);

            //Assert
            Assert.IsNotNull(EncryptedMessage);
            Assert.AreNotEqual<string>(OriginalMessage, EncryptedMessage);
        }

        [TestMethod]
        public void PrivateDecryptTest()
        {
            //Arrange
            if (EncryptedMessage == null)
            {
                DecryptedMessage = null;
                PublicEncryptTest();
            }

            //Act
            DecryptedMessage = RSA.PrivateDecrypt(EncryptedMessage);

            //Assert
            Assert.IsNotNull(DecryptedMessage);
            Assert.AreEqual<string>(DecryptedMessage, OriginalMessage);
        }


        [TestMethod]
        public void SHA1SignTest()
        {
            //Arrange
            MessageSignature = null;
            OriginalMessage = DateTime.Now.ToString();
            if (RSA == null)
            {
                string privateKey = "";
                string publicKey = "";
                Sherwood.Security.KeyGenerationUtility.MainWindow.GenerateKeyPair(out publicKey, out privateKey);
                RSA = Rsa.FromPrivateKey(privateKey);
            }

            //Act
            MessageSignature = RSA.SHA1Sign(OriginalMessage);

            //Assert
            Assert.IsNotNull(MessageSignature);
            Assert.AreNotEqual<string>(MessageSignature, OriginalMessage);
        }

        [TestMethod]
        public void SHA1VerifyTest()
        {
            //Arrange
            SHA1SignTest();
            string fakeMessage = DateTime.Now.AddDays(1).ToString();
            string fakeSignature = RSA.SHA1Sign(fakeMessage);

            //Act
            bool verified = RSA.SHA1Verify(OriginalMessage, MessageSignature);
            bool verifiedWrongMessage = RSA.SHA1Verify(fakeMessage, MessageSignature);
            bool verifiedWrongSignature = RSA.SHA1Verify(OriginalMessage, fakeSignature);
            bool verifiedNullMessage = RSA.SHA1Verify(null, MessageSignature);
            bool verifiedNullSignature = RSA.SHA1Verify(OriginalMessage, null);
            bool verifiedEmptySignature = RSA.SHA1Verify(OriginalMessage, "");

            //Assert
            Assert.IsTrue(verified);
            Assert.IsFalse(verifiedWrongMessage);
            Assert.IsFalse(verifiedWrongSignature);
            Assert.IsFalse(verifiedNullMessage);
            Assert.IsFalse(verifiedNullSignature);
            Assert.IsFalse(verifiedEmptySignature);

        }
    }
}
